/**
 *  Return a SkImage using the encoded data, but attempts to defer decoding until the
 *  image is actually used/drawn. This deferral allows the system to cache the result, either on the
 *  CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
 *  be purged, causing the next draw of the image to have to re-decode.
 *
 *  If alphaType is nullopt, the image's alpha type will be chosen automatically based on the
 *  image format. Transparent images will default to kPremul_SkAlphaType. If alphaType contains
 *  kPremul_SkAlphaType or kUnpremul_SkAlphaType, that alpha type will be used. Forcing opaque
 *  (passing kOpaque_SkAlphaType) is not allowed, and will return nullptr.
 *
 *  If the encoded format is not supported, nullptr is returned.
 *
 *  @param encoded  the encoded data
 *  @return         created SkImage, or nullptr

    example: https://fiddle.skia.org/c/@Image_DeferredFromEncodedData
*/

#ifndef SkImage_OH_DEFINED
#define SkImage_OH_DEFINED

#include "include/core/SkBitmap.h"
#include "include/core/SkImage.h"
#include "include/core/SkPixelRef.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkImagePriv.h"
#include "src/core/SkMipmap.h"
#include "src/image/SkImage_Base.h"

#include <atomic>
#include <cstddef>
#include <cstdint>
#include <multimedia/image_framework/image/image_source_native.h>
#include <utility>

class SkImage_OH : public SkImage_Base {
public:
    SkImage_OH(const SkImageInfo &info, OH_ImageSourceNative *source, float rotateDegree = 0.f, bool needFlip = false,
               uint32_t id = kNeedNewImageUniqueID)
        : SkImage_OH(info, source, 0, true, rotateDegree, needFlip, id) {}
    SkImage_OH(const SkImageInfo &, OH_ImageSourceNative *, int frameIndex, bool sourceNeedRelease = true,
               float rotateDegree = 0.f, bool needFlip = false, uint32_t id = kNeedNewImageUniqueID);
    SkImage_OH(const SkImageInfo &, OH_PixelmapNative *, uint32_t id = kNeedNewImageUniqueID);
    
    ~SkImage_OH() override;

    // From SkImage.h
    bool isValid(GrRecordingContext* context) const override;

    bool getScalePixels(SkBitmap &dst, const SkSamplingOptions &,
                       CachingHint cachingHint = kAllow_CachingHint) const override;
    
    // From SkImage_Base.h
    bool onReadPixels(GrDirectContext*, const SkImageInfo&, void*, size_t, int srcX, int srcY,
                      CachingHint) const override;

    bool getROPixels(GrDirectContext*, SkBitmap*, CachingHint) const override;
    sk_sp<SkData> encodeToData(SkEncodedImageFormat encodedImageFormat, int quality) const override;
    sk_sp<SkImage> onMakeSubset(GrDirectContext*, const SkIRect&) const override;
    sk_sp<SkImage> onMakeSubset(skgpu::graphite::Recorder*,
                                const SkIRect&,
                                RequiredProperties) const override;

    sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>,
                                                GrDirectContext*) const override;

    sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;

    void notifyAddedToRasterCache() const override {
        // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
        // lifetime of derived/cached resources to the image. In this case, we only want cached
        // data (eg mips) tied to the lifetime of the underlying pixelRef.
        if (fPixelRef) {
            fPixelRef->notifyAddedToCache();
        }
    }

    bool onHasMipmaps() const override { return false; }

    sk_sp<SkImage> onMakeWithMipmaps(sk_sp<SkMipmap> mips) const override {
        return nullptr;
    }

    SkImage_Base::Type type() const override { return SkImage_Base::Type::kLazy; }
    
    void buildPixelmap(int width, int height, int index, OH_PixelmapNative** dst = nullptr) const;
    void tryRebuildPixelRef() const;
    OH_Drawing_PixelMap* getOHPixelmap(int width = 0, int height = 0) const override;
    OH_Drawing_Image* getOHDrawingImage(int width = 0, int height = 0) const override;
    uint64_t hash() const override;

private:
    mutable sk_sp<SkPixelRef> fPixelRef;
    OH_ImageSourceNative* fImageSource = nullptr;
    float fRotateDegree = 0.f;
    bool fNeedFlip = false;
    bool fSourceNeedRelease = false;
    int fFrameIndex = 0;
    mutable std::atomic<OH_PixelmapNative*> fDecodePixelmap = nullptr;
    
};


#endif // SkImage_OH_DEFINED